<?php

namespace core;

use Exception;
use InvalidArgumentException;

require_once 'functions.php';

class App
{
    public function __construct()
    {
        $this->setEnv();
        $this->route();
    }

    /**
     * 环境配置
     */
    private function setEnv()
    {
        // 显示所有错误
        error_reporting(E_ALL);

        // 确认日志目录存在
        path_sure(LOG_PATH);

        if (APP_DEBUG) {
            ini_set('display_errors', 'On'); //调试模式，网页显示错误信息
        } else {
            ini_set('display_errors', 'Off'); //线上模式网页不显示错误信息
            ini_set('log_errors', 'On'); //记录错误日志
        }

        ini_set('date.timezone', 'Asia/Shanghai'); //设置时区
    }

    /**
     * 路由
     */
    private function route()
    {
        // 解析请求的URI以获取路由信息
        $routeInfo = $this->parseRequestUriToRouteInfo();
        // 解析并设置路由默认值
        [$app, $controller, $method] = $this->getDefaultRouteValues($routeInfo);

        define('APP', $app);
        define('CONTROLLER', $controller);
        define('METHOD', $method);

        $controllerFile = ucfirst($controller);
        $controllerClass = "app\\{$app}\\controllers\\{$controllerFile}";

        if (class_exists($controllerClass)) {
            //执行控制器类方法
            (new $controllerClass($method))->{$method}();
        } else {
            // 适当地处理错误，例如抛出异常或显示错误消息
            throw new Exception("Controller class '{$controllerClass}' does not exist.");
        }
    }

    /**
     * 解析请求的URI以获取路由信息
     *
     * @return array|null 返回解析后的路由信息，如果解析失败则返回null
     */
    private function parseRequestUriToRouteInfo()
    {
        $originalUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        $routeInfo = $this->parseUriToModuleControllerAction($originalUri);

        return $routeInfo;
    }

    /**
     * 解析并设置路由默认值
     *
     * @param array $routeInfo 路由信息数组
     *
     * @return array 包含应用、控制器和方法的数组
     */
    private function getDefaultRouteValues(array $routeInfo)
    {
        $app        = $routeInfo[0] ?? DEFAULT_APP;
        $controller = $routeInfo[1] ?? DEFAULT_CONTROLLER;
        $method     = $routeInfo[2] ?? DEFAULT_METHOD;

        // 控制器文件路径构建
        $controllerFile = APP_PATH . $app . '/controllers/' . ucfirst($controller) . '.php';
        // 检查控制器文件是否存在，同时防止目录遍历攻击
        if (!empty($controller) && strpos($controller, '..') === false && !file_exists($controllerFile)) {
            $controller = DEFAULT_CONTROLLER;
            // 保持用户可能指定的方法，否则使用默认方法
            $method = isset($routeInfo[1]) ? $routeInfo[1] : DEFAULT_METHOD;
        }

        return [$app, $controller, $method];
    }

    /**
     * 解析URI以提取模块、控制器和动作。
     *
     * @param string $uri    请求URI。
     * @param string $prefix 要从URI中去除的前缀（默认为'/'）。
     *
     * @return array 包含模块、控制器和动作（如果可用）的数组。
     */
    private function parseUriToModuleControllerAction(string $uri, string $prefix = '/')
    {
        // 移除URI中的前缀
        $uri = substr($uri, strlen($prefix));

        // 防止目录遍历攻击
        if (strpos($uri, '..') !== false) {
            throw new InvalidArgumentException('无效URI: 检测到潜在的目录遍历。');
        }

        // 移除可能存在的文件扩展名
        [$cleanUri, ] = explode('.', $uri, 2);

        // 分割URI成多个部分，并移除空部分
        $segments = array_filter(explode('/', $cleanUri), 'strlen');

        // 返回解析后的部分
        return $segments;
    }
}
